home *** CD-ROM | disk | FTP | other *** search
- /* ----------------------------------------------------------------------
- cimon - a UNIX command line client for the fli4l imon daemon.
-
- Public domain, 2001-2002, Rene Herman <rene.herman@mail.com>
- ---------------------------------------------------------------------- */
-
- #include <signal.h>
- #include <string.h> /* FD_ZERO expands to bzero() on MacOS X */
-
- #include <unistd.h>
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/time.h>
-
- #ifdef __EMX__ /* EMX fails to declare select() in unistd.h */
- #include <sys/select.h>
- #endif
-
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
-
- #include "cimon.h"
-
- /*--- globals */
-
- unsigned short port = IMON_PORT; /* TCP port number */
- const char *password; /* imond password */
-
- /*--- filescopes */
-
- static int sock; /* socket */
- static int empty = 1; /* communications channel empty */
-
- #define BUFF_SIZE 4096 /* 0 < BUFF_SIZE <= SSIZE_MAX */
- static char buff[BUFF_SIZE]; /* command/reply buffer */
- static int bufc = 0; /* buffer counter */
-
- /*--- private functions */
-
- static void buff_send(void)
- {
- if (write(sock, buff, bufc) != bufc)
- exit_errno("Write error");
- empty = bufc = 0;
- }
-
- static void buff_putc(const char c)
- {
- if (bufc == BUFF_SIZE)
- buff_send();
- buff[bufc++] = c;
- }
-
- static void buff_puts(const char *s)
- {
- while (*s)
- buff_putc(*s++);
- }
-
- static void send_command(void)
- {
- buff_putc('\r');
- buff_putc('\n');
- buff_send();
- }
-
- static void send_quit(void)
- {
- buff_puts("quit");
- send_command();
- }
-
- #define REPLY_OK 1
- #define REPLY_ERR 2
-
- static void get_reply(void)
- {
- static char *s;
- static char c = '\n';
-
- fd_set sockset;
- struct timeval timeout;
- int i;
-
- /* 10 second timeout */
- FD_ZERO(&sockset);
- FD_SET(sock, &sockset);
- timeout.tv_sec = 10;
- timeout.tv_usec = 0;
-
- if ((i = select(sock + 1, &sockset, NULL, NULL, &timeout)) < 0)
- exit_errno("Internal error (select)");
- else if (!i)
- exit_error("Timeout waiting for reply from remote");
-
- if ((i = read(sock, buff, BUFF_SIZE)) < 0)
- exit_errno("Read error");
- else if (!i)
- exit_error("Connection closed by remote");
-
- /* scan for (\n terminated) line starting with OK or ERR */
- do {
- if (c == '\n')
- s = buff[bufc] == 'O' ? "K" : buff[bufc] == 'E' ? "RR" : NULL;
- else if (s && *s && buff[bufc] != *s++)
- s = NULL;
- c = buff[bufc++];
- } while (--i);
-
- /* "empty" doubles as OK/ERR indicator */
- empty = s && !*s && c == '\n' ?
- (*(s - 1) == 'K' ? REPLY_OK : REPLY_ERR) : 0;
- }
-
- static void send_command_get_reply()
- {
- send_command();
- do {
- get_reply();
- write(STDOUT_FILENO, buff, bufc);
- bufc = 0;
- } while (!empty);
- }
-
- static void check_password(void)
- {
- buff_puts("pass ");
- buff_puts(password);
- send_command();
- do {
- get_reply();
- bufc = 0;
- } while (!empty);
- if (empty != REPLY_OK) {
- send_quit();
- exit_error("Password rejected by remote");
- }
- }
-
- static void flush()
- {
- if (bufc || !empty)
- send_command_get_reply();
- }
-
- /*--- global functions */
-
- void imon_open(const char * const hostname)
- {
- struct sockaddr_in name;
- struct hostent *host;
-
- name.sin_family = AF_INET;
- name.sin_port = htons(port);
- if ((name.sin_addr.s_addr = inet_addr(hostname)) == INADDR_NONE) {
- if (!(host = gethostbyname(hostname)))
- exit_error("Can't find `%s': %s", hostname, herrorstr(h_errno));
- name.sin_addr = *(struct in_addr *)host->h_addr;
- }
-
- if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
- exit_errno("Error creating socket");
- if (connect(sock, (struct sockaddr *)&name, sizeof name))
- exit_errno(hostname);
-
- if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
- exit_errno("Internal error (signal)");
-
- if (password)
- check_password();
- }
-
- void imon_putc(const char c)
- {
- if (c == '\n')
- flush();
- else
- buff_putc(c);
- }
-
- void imon_puts(const char *s)
- {
- while (*s)
- imon_putc(*s++);
- }
-
- void imon_quit(void)
- {
- flush();
- send_quit();
- if (close(sock))
- exit_errno("Can't close connection");
- }
-